﻿using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;

namespace Microsoft.Coding4Fun.TweetCraft.Targa
{
    internal static class BitmapExtensions
    {
        private const int PixelDepth = 24;

        /// <summary>
        /// Saves the <see cref="Image"/> to a 32-bit, uncompressed Truevision Targa file.
        /// </summary>
        /// <param name="bitmap">The bitmap to save.</param>
        /// <param name="filename">The filename to save the image to.</param>
        public static void SaveTarga(this Bitmap bitmap, string filename)
        {
            if (bitmap == null)
                throw new ArgumentNullException("bitmap");
            if (filename == null)
                throw new ArgumentNullException("filename");

            // Open a FileStream with Write access to the filename
            using (FileStream stream = File.OpenWrite(filename))
            {
                // Initialize a BinaryWriter for the stream
                using (var writer = new BinaryWriter(stream))
                {
                    // Construct the Targa header for the image
                    var header = new TargaHeader(bitmap.Width, bitmap.Height, PixelDepth);

                    // Write the header
                    writer.WriteStruct(header);

                    // Flip the image vertically
                    bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);

                    // Lock the bitmap
                    BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);

                    try
                    {
                        // Declare an array to hold the bytes of the bitmap
                        int bitmapDataSize = bitmapData.Stride * bitmapData.Height;
                        var bitmapDataArray = new byte[bitmapDataSize];

                        // Copy the RGB values into the array.
                        Marshal.Copy(bitmapData.Scan0, bitmapDataArray, 0, bitmapDataSize);

                        // Unlock the bits as early as possible
                        bitmap.UnlockBits(bitmapData);

                        // Null out the BitmapData class as we've already unlocked it
                        bitmapData = null;

                        // Flip the image back
                        bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY);

                        // Write the bitmap to the file stream
                        writer.Write(bitmapDataArray);
                    }
                    finally
                    {
                        // Make sure the bits are unlocked, if not unlocked yet
                        if (bitmapData != null)
                        {
                            // Unlock the bitmap data
                            bitmap.UnlockBits(bitmapData);
                        }
                    }
                }
            }
        }
    }
}